/*
 * @Description:
 * @Author: Dxcr
 * @Date: 2024-06-26 15:06:00
 * @LastEditTime: 2024-07-09 15:51:29
 * @LastEditors: Dxcr
 */
import * as THREE from "three";
import DxcrWebWorker from "dxcr-webworker";
import { ThreejsUtill } from "dxcr-three";
import VisualMap from "./visualMap";
import Stats from "three/addons/libs/stats.module.js";
import dayjs from "dayjs";
import colors from "./colors";
class Waterfall {
  // 组件
  dom;
  scene;
  camera;
  renderer;
  stats;
  webWorker;

  // 数据处理
  geometry;
  material;
  attributesUpdateFlag = false;
  countBuffer = 0;
  //
  canvas;
  chartContext;
  canvasTexture;
  chartMesh;
  // 坐标轴
  yAxis;
  yAxisData = [];
  font;
  tickNum = 0;
  scrollCount = 0;
  xAxis;
  xAxisData = [];
  xAxisOptions = {
    color: 0xffffff,
    showCount: 10,
  };
  yAxisOptions = {
    color: 0xffffff,
    showCount: 10,
  };
  //坐标轴指示器
  xAxisPointer;
  yAxisPointer;
  xAxisPointerText;
  yAxisPointerText;
  currentCoordinate;
  //图表
  rawData = [];
  chartData = [];
  rawDataCount;

  //选中区域
  range = [0, 1];
  rangeArea = [0, 0];
  rangeAreaMesh;
  // 参数
  dataCount = 1000;
  keepCount = 500;

  visualMapOptions = {
    height: 100,
    width: 20,
    paddingLeft: 20,
    paddingRight: 10,
    show: false,
  };

  minValue = 0;
  maxValue = 1000;
  paddingLeft = 0;
  paddingRight = 10;
  paddingTop = 10;
  paddingBottom = 0;
  chartWidth = 1000;
  chartHeight = 500;
  axisWidth = 120;
  axisHeight = 20;
  tickInterval = 20;
  subTickInterval = 5;
  debugMode = false;
  width = 500;
  height = 500;
  constructor(dom, options = {}) {
    this.dom = dom;
    this.dom.style.position = "relative";
    // this.width =
    //   this.axisWidth +
    //   this.chartWidth +
    //   this.paddingLeft +
    //   this.paddingRight +
    //   1;
    // this.height =
    //   this.axisHeight +
    //   this.chartHeight +
    //   1 +
    //   this.paddingBottom +
    //   this.paddingTop;

    this.paddingTop = options.paddingTop || this.paddingTop;
    this.paddingBottom = options.paddingBottom || this.paddingBottom;
    this.paddingLeft = options.paddingLeft || this.paddingLeft;
    this.paddingRight = options.paddingRight || this.paddingRight;
    this.width = dom.clientWidth;
    this.height = dom.clientHeight;
    this.chartWidth =
      this.width - this.axisWidth - this.paddingLeft - this.paddingRight;
    this.chartHeight =
      this.height - this.axisHeight - this.paddingTop - this.paddingBottom;

    this.dataCount = options.dataCount || this.dataCount;
    this.keepCount = options.keepCount || this.keepCount;
    // this.chartWidth = options.chartWidth || this.chartWidth;
    // this.chartHeight = options.chartHeight || this.chartHeight;
    this.debugMode = options.debugMode || this.debugMode;
    this.rawDataCount = options.rawDataCount || this.dataCount;
    this.minValue = options.minValue || this.minValue;
    this.maxValue = options.maxValue || this.maxValue;
    this.xAxisOptions = Object.assign(this.xAxisOptions, options.xAxisOptions);
    this.yAxisOptions = Object.assign(this.yAxisOptions, options.yAxisOptions);
    this.visualMapOptions = Object.assign(this.visualMapOptions, options.visualMapOptions);

    this.init();
  }

  init() {
    if (this.visualMapOptions.show) {
      this.chartWidth -=
        this.visualMapOptions.width +
        this.visualMapOptions.paddingLeft +
        this.visualMapOptions.paddingRight;
      this.initVisualMap();
    }

    this.initThree();
    this.initWebWorker();

    if (this.debugMode) {
      console.log("waterfall - Init");
      this.initStats();
    }

    // this.handleVisibilityChange();
  }

  initWebWorker() {
    let c = this;
    this.webWorker = new DxcrWebWorker(
      "/dxcr-waterfall/Worker/worker.js",
      { type: "module" },
      {
        onMessage: (event) => {
          // console.log('WebWorker Received:', event.data)
          let returnObject = event.data;
          let type = returnObject.type;
          let data = returnObject.data;

          if (type == 1) {
            c.updateDataAll(data);
          } else {
            c.updateData(data, returnObject.index);
          }
        },
        onError: (event) => console.error("WebWorker error:", event),
      }
    );
  }

  initVisualMap() {
    const visualMap = new VisualMap(this.dom);
    this.visualMap = visualMap
    // 将 RGB 数组转换为 CSS 颜色字符串
    const rgbToCssColor = (rgb) =>
      `rgb(${rgb.map((val) => Math.round(val * 255)).join(", ")})`;
    // 创建颜色渐变字符串
    const gradient = colors.map(rgbToCssColor);
    visualMap.updateVisualMap(gradient, this.minValue, this.maxValue);
    visualMap.visualMapDom.style.position = "absolute";
    visualMap.visualMapDom.style.bottom = "20px";
    visualMap.visualMapDom.style.right = "20px";
    visualMap.bindLabelDoubleClick((type, data) => {
      if (type == 0) {
        this.minValue = data;
      } else {
        this.maxValue = data;
      }
      this.setData(this.rawData);
    });
  }

  addData(data, index) {
    this.webWorker.postMessage({
      data: data,
      index: index,
      type: 0,
      minValue: this.minValue,
      maxValue: this.maxValue,
      dataCount: this.dataCount,
    });
  }

  setData(data) {
    this.rawData = data;
    this.webWorker.postMessage({
      data: data,
      type: 1,
      minValue: this.minValue,
      maxValue: this.maxValue,
      dataCount: this.dataCount,
    });
  }

  setColorValue(minValue, maxValue) {
    this.minValue = minValue || this.minValue;
    this.maxValue = maxValue || this.maxValue;
    const rgbToCssColor = (rgb) =>
      `rgb(${rgb.map((val) => Math.round(val * 255)).join(", ")})`;
    const gradient = colors.map(rgbToCssColor);
    this.visualMap.updateVisualMap(gradient, this.minValue, this.maxValue);
  }

  clearData() {
    this.chartData = [];
    this.updateChartAll(this.chartData);
  }

  handleVisibilityChange() {
    const c = this;
    // 处理页面可见性变化
    document.addEventListener("visibilitychange", function () {
      if (document.visibilityState === "visible") {
        // 强制更新所有几何体属性
        c.geometry.attributes.position.updateRange.offset = 0;
        c.geometry.attributes.position.updateRange.count = -1;
        c.geometry.attributes.position.needsUpdate = true;

        c.geometry.attributes.color.updateRange.offset = 0;
        c.geometry.attributes.color.updateRange.count = -1;
        c.geometry.attributes.color.needsUpdate = true;
      }
    });
  }

  resizeChart() {
    this.range = [0, 1];
    this.scaleChart(this.range);
  }

  scaleChart(range) {
    let startUV = range[0] > range[1] ? range[1] : range[0];
    let endUV = range[0] > range[1] ? range[0] : range[1];
    //改变uv坐标
    let uv = this.geometry.attributes.uv.array;
    for (let i = 0; i < uv.length; i += 2) {
      if (i < uv.length / 2) {
        uv[i] = startUV;
      } else {
        uv[i] = endUV;
      }
    }
    this.geometry.attributes.uv.needsUpdate = true;

    let start = Math.floor(startUV * this.rawDataCount);
    let end = Math.floor(endUV * this.rawDataCount);
    this.xAxisData = this.generateXDatas(start, end);
    this.updateXAxis();
  }

  scaleDatas(datas, range) {
    let count = datas[0].length;
    let startRange = range[0] || 0;
    let endRange = range[1] || count;
    const sliceData = datas.map((data) => {
      return data.slice(startRange, endRange);
    });
    return sliceData;
  }

  scaleData(data, range) {
    let count = data.length;
    let startRange = range[0] || 0;
    let endRange = range[1] || count;
    return data.slice(startRange, endRange);
  }

  initXAxis() {
    this.xAxisData = this.generateXDatas();
    this.updateXAxis();
  }

  updateData(dataColors, index) {
    // console.log("dataColors", dataColors);
    let rollIndex = index % this.keepCount;
    this.chartData[rollIndex] = dataColors;

    this.updateChart(dataColors, rollIndex);
    this.updateYAxis(index);
    if (index >= this.keepCount) {
      this.scroll();
    }
  }

  updateDataAll(datasArray) {
    this.clearTick();
    this.updateAllYAxis();
    this.chartData = datasArray;
    this.updateChartAll(datasArray);
  }

  updateChartAll(datasArray) {
    let c = this;
    this.clearChart();
    let y = 0;
    let width = this.chartWidth / this.dataCount;
    let height = this.chartHeight / this.keepCount;
    for (let i = 0; i < datasArray.length; i++) {
      let colors = datasArray[i];

      let x = 0;
      for (let j = 0; j < colors.length; j += 3) {
        const cssColor = `rgb(${Math.round(colors[j] * 255)},${Math.round(
          colors[j + 1] * 255
        )},${Math.round(colors[j + 2] * 255)})`;
        this.chartContext.fillStyle = cssColor;
        // this.chartContext.fillStyle = "rgb(64, 150, 255)";
        this.chartContext.fillRect(
          x,
          this.canvas.height - 1 - y,
          width,
          height
        );
        x += width;
      }
      y += height;
    }

    // 创建纹理
    const texture = new THREE.CanvasTexture(this.canvas);
    texture.wrapS = THREE.RepeatWrapping;
    texture.wrapT = THREE.RepeatWrapping;
    texture.magFilter = THREE.NearestFilter;
    texture.minFilter = THREE.NearestFilter;
    this.material.map = texture;
    this.material.needsUpdate = true;
  }

  updateChart(colors, index) {
    let c = this;

    // 绘制纹理图内容
    let width = this.chartWidth / this.dataCount;
    let height = this.chartHeight / this.keepCount;
    let x = 0;
    let y = this.canvas.height - height - index * height;
    this.clearChart(0, y, this.canvas.width, height);
    for (let i = 0; i < colors.length; i += 3) {
      const cssColor = `rgb(${Math.round(colors[i] * 255)}, ${Math.round(
        colors[i + 1] * 255
      )}, ${Math.round(colors[i + 2] * 255)})`;
      this.chartContext.fillStyle = cssColor;
      this.chartContext.fillRect(x, y, width, height);
      x += width;
    }

    // 创建纹理
    const texture = new THREE.CanvasTexture(this.canvas);
    texture.wrapS = THREE.RepeatWrapping;
    texture.wrapT = THREE.RepeatWrapping;
    texture.magFilter = THREE.NearestFilter;
    texture.minFilter = THREE.NearestFilter;
    this.material.map = texture;
    this.material.needsUpdate = true;
  }

  updateChartGradient(colors, index) {
    // 创建线性渐变色对象
    let gradient = this.chartContext.createLinearGradient(
      0,
      0,
      this.canvas.width,
      0
    );
    // 绘制纹理图内容
    for (let i = 0; i < colors.length; i += 3) {
      // 设置渐变色的起止颜色
      // 假设colors数组是颜色值的线性索引或直接存储颜色值
      const cssColor = `rgb(${Math.round(colors[i] * 255)}, ${Math.round(
        colors[i + 1] * 255
      )}, ${Math.round(colors[i + 2] * 255)})`;
      gradient.addColorStop(i / (colors.length - 3), cssColor);
    }

    // 使用渐变色填充矩形
    this.chartContext.fillStyle = gradient;

    this.chartContext.fillRect(
      0,
      this.canvas.height - index,
      this.canvas.width,
      1
    );

    // 创建纹理
    const texture = new THREE.CanvasTexture(this.canvas);
    texture.wrapS = THREE.RepeatWrapping;
    texture.wrapT = THREE.RepeatWrapping;
    texture.magFilter = THREE.NearestFilter;
    texture.minFilter = THREE.NearestFilter;
    this.material.map = texture;
    this.material.needsUpdate = true;
  }

  clearChart(
    x = 0,
    y = 0,
    width = this.canvas.width,
    height = this.canvas.height
  ) {
    this.chartContext.clearRect(x, y, width, height);
  }

  scroll() {
    let c = this;
    // 关键代码 更新了边界球体 解决了超出一定范围不显示的bug
    if (this.scrollCount % (this.chartHeight / 2) < 1) {
      this.geometry.computeBoundingSphere();
      this.yAxis.geometry.computeBoundingSphere();
    }
    this.scrollCount++;

    this.updateAxis(this.yAxis);
    this.rollChart(this.scrollCount);
  }

  rollChart(index) {
    let texture = this.material.map;
    texture.offset.y = (index * (1 / this.keepCount)) % 1;
  }

  initThree() {
    // 创建场景和相机
    this.scene = new THREE.Scene();

    // 宽高要+1 防止第一条数据丢失
    this.camera = new THREE.OrthographicCamera(
      -this.width / 2, // 左
      this.width / 2, // 右
      this.height / 2, // 上
      -this.height / 2, // 下
      1,
      1000
    );
    this.camera.position.set(this.width / 2, this.height / 2, 100);

    // 创建渲染器
    const renderer = new THREE.WebGLRenderer();
    renderer.setClearColor(0xb9d3ff, 0.0);
    this.renderer = renderer;
    renderer.setSize(this.width, this.height);
    this.dom.appendChild(renderer.domElement);

    // 创建几何体
    let geometry = new THREE.BufferGeometry();
    this.geometry = geometry;

    //类型化数组创建顶点数据
    const vertices = new Float32Array([
      0,
      0,
      0, //顶点1坐标
      0,
      this.chartHeight,
      0, //顶点2坐标
      this.chartWidth,
      this.chartHeight,
      0, //顶点3坐标
      this.chartWidth,
      0,
      0, //顶点4坐标
    ]);

    // 创建索引数组
    const indices = new Uint16Array([
      0,
      1,
      2, // 三角形1
      0,
      2,
      3, // 三角形2
    ]);

    // 创建属性缓冲区对象
    const attribue = new THREE.BufferAttribute(vertices, 3);
    geometry.setAttribute("position", attribue);
    geometry.setIndex(new THREE.BufferAttribute(indices, 1));

    // 创建纹理坐标
    const uv = new Float32Array([
      0,
      0, // 顶点1的纹理坐标
      0,
      1, // 顶点2的纹理坐标
      1,
      1, // 顶点3的纹理坐标
      1,
      0, // 顶点4的纹理坐标
    ]);

    geometry.setAttribute("uv", new THREE.BufferAttribute(uv, 2));

    const material = new THREE.MeshBasicMaterial({
      color: "#ffffff", //材质颜色
      map: null,
      // side: THREE.FrontSide, //默认只有正面可见
      side: THREE.DoubleSide, //两面可见
      // side: THREE.BackSide, //设置只有背面可见
    });
    // material.onBeforeCompile = function (shader, renderer) {
    //   console.log('shader',shader)
    //   // shader.uniforms.diffuse.value = null
    //   console.log('renderer',renderer)
    // };
    this.material = material;

    const chartMesh = new THREE.Mesh(geometry, material);
    chartMesh.name = "chart";
    this.chartMesh = chartMesh;
    chartMesh.position.set(this.axisWidth, this.axisHeight, 0);
    this.scene.add(chartMesh);

    this.initTicks();
    this.initXAxis();
    this.initCanvas();
    this.initAxisPointer();
    this.initRangeArea();
    this.addEvent();
    // 渲染
    this.animate();
  }

  addEvent() {
    let c = this;
    // 监听鼠标按下事件
    let mouseDown = false;
    let startUV = new THREE.Vector2();
    let endUV = new THREE.Vector2();
    // 创建射线投射器
    let dom = this.renderer.domElement;
    this.renderer.domElement.addEventListener("mousedown", (event) => {
      mouseDown = false;

      // 将鼠标位置转换为NDC坐标
      let mouse = new THREE.Vector2();
      mouse.x = (event.offsetX / dom.clientWidth) * 2 - 1;
      mouse.y = -(event.offsetY / dom.clientHeight) * 2 + 1;

      // 使用射线投射器和相机来检测点击的对象
      const raycaster = new THREE.Raycaster();
      raycaster.setFromCamera(mouse, c.camera);
      let intersects = raycaster.intersectObjects(c.scene.children, true);

      if (intersects.length > 0) {
        // 获取第一个交点的对象
        let clickedObject = intersects[0].object;
        // console.log("Clicked object:", clickedObject);
        let name = clickedObject.name;
        if (name == "chart") {
          let uv = intersects[0].uv;
          startUV = uv;
          c.range[0] = startUV.x;

          let point = intersects[0].point;
          c.rangeArea[0] = point.x;

          mouseDown = true;
        }
      }
    });

    // 监听鼠标移动事件
    this.renderer.domElement.addEventListener("mousemove", (event) => {
      // console.log("mousemove");
      // 将鼠标位置转换为NDC坐标
      let mouse = new THREE.Vector2();
      mouse.x = (event.offsetX / dom.clientWidth) * 2 - 1;
      mouse.y = -(event.offsetY / dom.clientHeight) * 2 + 1;

      // 使用射线投射器和相机来检测点击的对象
      const raycaster = new THREE.Raycaster();
      raycaster.setFromCamera(mouse, c.camera);
      let intersects = raycaster.intersectObjects(c.scene.children, true);

      if (intersects.length > 0) {
        // 获取第一个交点的对象
        let clickedObject = intersects[0].object;
        let name = clickedObject.name;
        if (name == "chart") {
          if (mouseDown) {
            let uv = intersects[0].uv;
            endUV = uv;
            c.range[1] = endUV.x;

            let point = intersects[0].point;
            c.rangeArea[1] = point.x;
            c.updateRangeArea();
          }

          let clickedPoint = intersects[0].point;
          let x = clickedPoint.x - clickedObject.position.x;
          let y = clickedPoint.y - clickedObject.position.y;
          c.currentCoordinate = { x, y };
        }
      }
    });

    // 监听鼠标释放事件
    this.renderer.domElement.addEventListener("mouseup", (event) => {
      if (mouseDown) {
        // 将鼠标位置转换为NDC坐标
        let mouse = new THREE.Vector2();
        mouse.x = (event.offsetX / dom.clientWidth) * 2 - 1;
        mouse.y = -(event.offsetY / dom.clientHeight) * 2 + 1;

        // 使用射线投射器和相机来检测点击的对象
        let raycaster = new THREE.Raycaster();
        raycaster.setFromCamera(mouse, c.camera);
        let intersects = raycaster.intersectObjects(c.scene.children, true);

        if (intersects.length > 0) {
          // 获取第一个交点的对象
          let clickedObject = intersects[0].object;
          // console.log("Clicked object:", clickedObject);
          let name = clickedObject.name;
          if (name == "chart") {
            //缩放
            let uv = intersects[0].uv;
            endUV = uv;
            //缩放矩阵
            if (startUV.x != endUV.x) {
              c.range[1] = endUV.x;
              //执行放大
              c.scaleChart(c.range);
            }
            c.showRangeArea(false);
          }
        }

        mouseDown = false;
      }
    });

    this.renderer.domElement.addEventListener("dblclick", () => {
      //还原矩阵
      c.resizeChart();
    });

    // 监听鼠标移出事件
    this.renderer.domElement.addEventListener("mouseout", function (event) {
      c.currentCoordinate = null;
    });
  }

  initCanvas() {
    this.canvas = document.createElement("canvas");
    // this.dom.appendChild(this.canvas);
    this.canvas.width = this.chartWidth;
    this.canvas.height = this.chartHeight;
    this.chartContext = this.canvas.getContext("2d");
    this.canvasTexture = new THREE.CanvasTexture(this.canvas);
    this.canvasTexture.wrapS = THREE.RepeatWrapping;
    this.canvasTexture.wrapT = THREE.RepeatWrapping;
    this.canvasTexture.magFilter = THREE.NearestFilter;
    this.canvasTexture.minFilter = THREE.NearestFilter;
    this.material.map = this.canvasTexture;
    this.material.needsUpdate = true;
  }

  animate() {
    ThreejsUtill.animateDelta((deltaTime) => {
      if (this.stats) {
        this.stats.update();
      }
      this.renderer.render(this.scene, this.camera);
      this.attributesUpdateFlag = false;
    });
  }

  initStats() {
    // 创建stats对象
    this.stats = new Stats();
    // Stats.domElement:web页面上输出计算结果,一个div元素
    this.dom.appendChild(this.stats.domElement);
    this.stats.domElement.style.position = "absolute";
    this.stats.domElement.style.bottom = "0px";
    this.stats.domElement.style.top = "auto";
  }

  createAxis(length, color) {
    const material = new THREE.LineBasicMaterial({
      color: color,
      linewidth: 10,
    });
    const points = [];
    points.push(new THREE.Vector3(0, 0, 0));
    points.push(new THREE.Vector3(length, 0, 0));
    const geometry = new THREE.BufferGeometry().setFromPoints(points);
    return new THREE.Line(geometry, material);
  }

  createTick(position, color, length = 10) {
    const material = new THREE.LineBasicMaterial({ color: color });
    const points = [];
    points.push(new THREE.Vector3(position, 0, 0));
    points.push(new THREE.Vector3(position, length, 0));
    const geometry = new THREE.BufferGeometry().setFromPoints(points);
    return new THREE.Line(geometry, material);
  }

  addTicks(axis, texts, color, tickInterval, subTickNum) {
    let arr = [];
    for (let i = 0; i < texts.length; i++) {
      let text = texts[i];
      let tickPosition = i * tickInterval;
      if (i == 0 && this.xAxis == axis) {
        tickPosition += 1;
      }
      if (i % subTickNum == 0) {
        let tick = this.addTick(axis, tickPosition, text, color, 6, -6);
        arr.push(tick);
      } else {
        let tick = this.addTick(axis, tickPosition, text, color, 6, -6);
        arr.push(tick);
      }
    }
    return arr;
  }

  addTick(axis, tickPosition, text, color, length, textDistance) {
    const tick = this.createTick(tickPosition, color, length);
    axis.add(tick);

    const sprite = this.createTextSprite(text, 12, "#ffffff", null, [2, 4]);
    sprite.position.x += tickPosition;
    sprite.position.y += textDistance;
    tick.add(sprite);

    return tick;
  }

  removeTick() {
    let tick = this.yAxis.children[0];
    this.yAxis.remove(tick);
  }

  initTicks() {
    const length = this.chartHeight;
    this.yAxis = this.createAxis(length, 0xffffff);
    this.yAxis.rotation.z = Math.PI / 2;
    this.yAxis.position.x = this.axisWidth + 1;
    this.yAxis.position.y = this.axisHeight;
    this.scene.add(this.yAxis);

    // 添加X轴
    let xAxisOptions = this.xAxisOptions;
    const xAxisLength = this.chartWidth;
    let xAxis = this.createAxis(xAxisLength, xAxisOptions.color); // 使用相同的颜色创建X轴
    this.xAxis = xAxis;
    this.xAxis.position.x = this.axisWidth; // 调整X轴的位置
    this.xAxis.position.y = this.axisHeight; // 调整X轴的位置
    this.scene.add(this.xAxis);
  }

  setYData(data) {
    this.yAxisData = data;
  }

  setXData(data) {
    this.xAxisData = data;
  }

  updateXAxis() {
    let xDatas = [];
    let showCount = this.xAxisOptions.showCount;
    for (let i = 0; i <= showCount; i++) {
      xDatas.push(
        this.xAxisData[
          Math.floor(((this.xAxisData.length - 1) / showCount) * i)
        ]
      );
    }
    this.xAxis.children = [];
    let ticks = this.addTicks(
      this.xAxis,
      xDatas,
      "#ffffff",
      this.chartWidth / (xDatas.length - 1),
      0
    );
    for (const tick of ticks) {
      tick.position.y = -6;
    }
  }

  //生成x轴文字
  generateXDatas(start = 0, end = this.rawDataCount) {
    let datas = [];
    for (let i = start; i <= end; i++) {
      datas.push(i);
    }
    return datas;
  }

  initRangeArea() {
    const rangeAreaMesh = this.createRangeArea({
      width: this.chartWidth,
      height: this.chartHeight,
    });
    rangeAreaMesh.position.x = this.chartWidth / 2;
    rangeAreaMesh.position.y = this.chartHeight / 2;
    this.chartMesh.add(rangeAreaMesh);
    rangeAreaMesh.visible = false;
    this.rangeAreaMesh = rangeAreaMesh;
  }

  updateRangeArea() {
    let AreaX = this.rangeArea[1] - this.rangeArea[0];
    let scaleX = AreaX / this.chartWidth;
    this.rangeAreaMesh.scale.x = scaleX;
    this.rangeAreaMesh.position.x =
      this.rangeArea[0] - this.chartMesh.position.x + AreaX / 2;
    this.rangeAreaMesh.visible = true;
  }

  showRangeArea(isShow = true) {
    this.rangeAreaMesh.visible = isShow;
    this.rangeAreaMesh.visible = isShow;
  }

  createRangeArea({ width, height }) {
    let material = new THREE.MeshBasicMaterial({
      color: 0xcccccc, // 设置材质颜色
      transparent: true, // 启用透明度
      opacity: 0.4, // 设置透明度为50%
    });
    let geometry = new THREE.PlaneGeometry(width, height);
    let mesh = new THREE.Mesh(geometry, material);
    return mesh;
  }

  showAxisPointer(isShow = true) {
    this.xAxisPointer.visible = isShow;
    this.yAxisPointer.visible = isShow;
  }

  updateAxisPointer() {
    if (this.currentCoordinate) {
      this.showAxisPointer();

      const { x, y } = this.currentCoordinate;
      this.xAxisPointer.position.x = x;
      this.yAxisPointer.position.y = y;
      this.updateAxisPointerText(x, y);
    } else {
      this.showAxisPointer(false);
    }
  }

  updateAxisPointerText(x, y) {
    let xIndex = Math.ceil((x / this.chartWidth) * this.rawDataCount);
    let yIndex = Math.floor((y / this.chartHeight) * this.chartHeight);
    xIndex = Math.min(xIndex, this.xAxisData.length - 1);
    yIndex = Math.min(yIndex, this.yAxisData.length - 1);
    let xText = this.xAxisData[xIndex] ?? "";
    let yText = this.yAxisData[yIndex] ?? "";

    const texture = this.createTextTexture(
      xText,
      12,
      "#ffffff",
      "#333333",
      [2, 4]
    );
    this.xAxisPointerText.material.map = texture;
    this.xAxisPointerText.scale.set(
      texture.image.width,
      texture.image.height,
      1
    );

    const texture1 = this.createTextTexture(
      yText,
      12,
      "#ffffff",
      "#333333",
      [2, 4]
    );
    this.yAxisPointerText.material.map = texture1;
    this.yAxisPointerText.scale.set(
      texture1.image.width,
      texture1.image.height,
      1
    );
  }

  initAxisPointer() {
    let c = this;
    let xAxisPointer = this.createXAxisPointer();
    this.xAxisPointer = xAxisPointer;
    xAxisPointer.visible = false;
    this.chartMesh.add(xAxisPointer);

    let yAxisPointer = this.createYAxisPointer();
    this.yAxisPointer = yAxisPointer;
    yAxisPointer.visible = false;
    this.chartMesh.add(yAxisPointer);

    const xAxisPointerText = this.createTextSprite(
      "",
      12,
      "#ffffff",
      "#333333",
      [2, 4]
    );
    xAxisPointerText.center = [0.5, 1];
    this.xAxisPointerText = xAxisPointerText;
    xAxisPointerText.position.y = -4;
    xAxisPointerText.position.z = 1;
    this.xAxisPointer.add(xAxisPointerText);

    const yAxisPointerText = this.createTextSprite(
      "",
      12,
      "#ffffff",
      "#333333",
      [2, 4]
    );
    yAxisPointerText.center = [1, 0.5];
    this.yAxisPointerText = yAxisPointerText;
    yAxisPointerText.position.x = -4;
    yAxisPointerText.position.z = 1;
    this.yAxisPointer.add(yAxisPointerText);

    ThreejsUtill.animate(() => {
      c.updateAxisPointer();
    });
  }

  createXAxisPointer() {
    const material = new THREE.LineBasicMaterial({
      color: "#ffffff",
      linewidth: 10,
    });
    const points = [];
    points.push(new THREE.Vector3(0, 0, 0));
    points.push(new THREE.Vector3(0, this.chartHeight, 0));
    const geometry = new THREE.BufferGeometry().setFromPoints(points);
    const line = new THREE.Line(geometry, material);
    return line;
  }

  createYAxisPointer() {
    const material = new THREE.LineBasicMaterial({
      color: "#ffffff",
      linewidth: 10,
    });
    const points = [];
    points.push(new THREE.Vector3(0, 0, 0));
    points.push(new THREE.Vector3(this.chartWidth, 0, 0));
    const geometry = new THREE.BufferGeometry().setFromPoints(points);
    const line = new THREE.Line(geometry, material);
    this.yAxisPointer = line;
    return line;
  }

  async initFont() {
    this.font = await ThreejsUtill.loadFont(
      "/fonts/Noto_Sans_SC/Noto Sans SC Light_Regular.json"
    );
    return this.font;
  }

  createTextTexture(
    text,
    fontSize,
    fontColor,
    backgroundColor,
    padding = [0, 0]
  ) {
    let paddingV = padding[0];
    let paddingH = padding[1];

    const canvas = document.createElement("canvas");
    const context = canvas.getContext("2d");

    context.font = `${fontSize}px 宋体`;
    // 设置画布尺寸
    const width = context.measureText(text).width;
    canvas.height = fontSize + paddingV * 2;
    canvas.width = width + paddingH * 2;
    //设置背景色
    if (backgroundColor) {
      context.fillStyle = backgroundColor;
      context.fillRect(0, 0, canvas.width, canvas.height);
    }
    //写字
    context.font = `${fontSize}px 宋体`;
    context.fillStyle = fontColor;

    // 绘制文字
    context.fillText(text, paddingH, canvas.height / 2 + fontSize / 2 - 2);
    // 创建纹理
    const texture = new THREE.CanvasTexture(canvas);
    texture.magFilter = THREE.NearestFilter;
    texture.minFilter = THREE.NearestFilter;
    return texture;
  }

  createTextSprite(
    text,
    fontSize,
    fontColor,
    backgroundColor,
    padding = [0, 0]
  ) {
    const texture = this.createTextTexture(
      text,
      fontSize,
      fontColor,
      backgroundColor,
      padding
    );
    const material = new THREE.SpriteMaterial({
      map: texture,
    });
    const sprite = new THREE.Sprite(material);
    // 根据字体大小调整精灵的比例
    sprite.scale.set(texture.image.width, texture.image.height, 1);
    return sprite;
  }

  updateAxis(yAxis) {
    let height = this.chartHeight / this.keepCount;
    // 改变原有坐标轴的点 后一个点坐标+1
    const position = yAxis.geometry.attributes.position;
    const numPoints = position.count; // 坐标轴线上的点的总数

    // 更新坐标轴线上每个点的位置
    for (let i = 0; i < numPoints; i++) {
      // 将每个点的 x 坐标增加 1
      position.setX(i, position.getX(i) + height);
    }
    position.needsUpdate = true;

    yAxis.position.y -= height;
  }

  updateYAxis(index, data) {
    data = data || dayjs().format("YYYY-MM-DD HH:mm:ss");
    this.yAxisData[index] = data;
    let y = index * (this.chartHeight / this.keepCount);
    if (index % this.tickInterval == 0) {
      this.addTick(this.yAxis, y, data, 0xffffff, 6, 70);
      this.tickNum++;
      //删除老的
      if (this.tickNum > this.keepCount / this.tickInterval) {
        this.removeTick();
        this.tickNum--;
      }
    }
  }

  updateAllYAxis() {
    let datas = [];
    let showCount = this.yAxisOptions.showCount;
    for (let i = 0; i <= showCount; i++) {
      datas.push(
        this.yAxisData[
          Math.floor(((this.yAxisData.length - 1) / showCount) * i)
        ]
      );
    }
    this.yAxis.children = [];
    let ticks = this.addTicks(
      this.yAxis,
      datas,
      "#ffffff",
      this.chartHeight / (datas.length - 1),
      0
    );
    for (const tick of ticks) {
      for (const children of tick.children) {
        children.position.y += 70;
      }
    }
  }

  clearTick() {
    this.yAxis.children = [];
    this.tickNum = 0;
  }
}

export default Waterfall;
